#pragma once
#include <cctype>
#include "elemtag.hpp"
template<int MAX_LINE_LEN = 65536>
struct scanner {
  char tokens[MAX_LINE_LEN];
  char *tptr;
  const char *sptr;
  char *next_tok() {
    const char *p = sptr;
    char *ret = tptr;
    while ((*p != 0) & (isspace(*p) != 0))
      p++;

    if (*p == 0)
      return NULL;

    while ((*p != 0) & (!isspace(*p))) {
      *(tptr++) = *(p++);
    }
    *(tptr++) = 0;

    sptr = p;

    return ret;
  }
  char set_input(const char *line) {
    tptr = tokens;
    sptr = line;
    while (isspace(*sptr))
      sptr++;
    return *sptr;
  }
  void parse(elemtag &dst, char *s) {
    dst.ival = 0;
    for (int i = 0; s[i]; i ++) {
      dst.ival |= s[i] << (i<<3);
    }
  }
  void parse(elemstr &dst, char *s) {
    strcpy(dst, s);
  }
  void parse(bool &dst, char *s) {
    dst = !strcmp(s, "true") || !strcmp(s, "yes");
  }
  void parse(const char* &dst, char *s) {
    dst = strdup(s);
  }
  void parse(real &val, char *s) {
    val = atof(s);
  }
  void parse(int &val, char *s) {
    val = atoi(s);
  }
  void parse(long &val, char *s) {
    val = atol(s);
  }
  void parse(char &val, char *s) {
    val = *s;
  }
  template <typename T>
  int safe_parse(T &val, char *s) {
    if (s == NULL)
      return 0;
    parse(val, s);
    return 1;
  }
  __always_inline int scan() {
    return 0;
  }
  template <typename T0, typename... Ts>
  __always_inline int scan(T0 &field0, Ts &...fields) {
    return safe_parse(field0, next_tok()) + scan(fields...);
  }
  template <typename... Ts, int... Is>
  __always_inline int apply_scan(std::tuple<Ts...> fields, utils::iseq<int, Is...> seq) {
    return scan(std::get<Is>(fields)...);
  }
  template <typename... Ts>
  __always_inline bool scan_all(Ts &...fields) {
    return scan(fields...) == sizeof...(Ts);
  }
  template <typename... Ts>
  __always_inline bool scan_all(std::tuple<Ts...> fields) {
    return apply_scan(fields, utils::make_iseq<int, sizeof...(Ts)>{}) == sizeof...(Ts);
  }
};